package com.shunlin.paopaoku.box2d;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.*;

import java.util.LinkedList;

import static com.shunlin.paopaoku.box2d.Box2DVars.*;

public class Box2DWorld {
    private World world; //世界类用于存放所有刚体
    public Body body; //刚体
    private BodyDef bdef; //刚体皮肤
    private FixtureDef fdef; //夹具皮肤
    private ChainShape chain; //链式图形
    private PolygonShape polygon; //多边形
    private Box2DDebugRenderer debug; //绘制Box2D的类
    public final int tileSize = 69; //瓦片大小

    public static LinkedList<Fixture> fixtureList; //存放刚体的集合
	
	private TiledMapTileLayer layer;

    private float x, y;

    public Box2DWorld() {
        init();
    }

    public void setObjectPosition(TiledMap map) {
        MapObject obj = map.getLayers().get("player").getObjects().get(0);
        x = (float) obj.getProperties().get("x");
        y = (float) obj.getProperties().get("y");
    }

    public void makePlayer() {
        bdef = new BodyDef();
        bdef.type = BodyDef.BodyType.DynamicBody; //设置刚体类型为动态就是可以移动的刚体
        bdef.position.set((x + tileSize) / 2 / PPM, (y + tileSize) / 2 / PPM); //设置刚体的位置 加tileSize再除以二是因为Box2d的坐标锚点和安卓的坐标锚点不一样
        body = world.createBody(bdef); //创建一个刚体,并引用刚体皮肤

        polygon = new PolygonShape();
        polygon.setAsBox(10 / PPM, 28 / PPM); //设置多边形为矩形

        fdef = new FixtureDef();
        fdef.shape = polygon; //设置夹具的形状为多边形的形状
		
		/*
			如果一个物体A目标属性等于另一个物体B的自身属性
			并且物体B的目标属性等于物体A的自身属性时会发生碰撞
		*/

        fdef.filter.categoryBits = BIT_PLAYER; //设置夹具的自身属性
        fdef.filter.maskBits = (short) (BIT_GROUND | BIT_STAR); //设置夹具的目标属性
        fdef.friction = 2f; //设置夹具的摩擦力

        body.createFixture(fdef).setUserData("player"); //设置夹具的数据，用于碰撞检测，拿到夹具判断是哪个刚体

        /////////////////////////////

        polygon.setAsBox(5 / PPM, 5 / PPM, new Vector2(0, -28 / PPM), 0);

        fdef.shape = polygon;
        fdef.isSensor = true; //设置为传感器，传感器就是和物体接触不会有反应，但是会被碰撞检测，检测到
        fdef.filter.categoryBits = BIT_PLAYER; //设置传感器的自身属性
        fdef.filter.maskBits = (short) (BIT_GROUND | BIT_STAR); //设置传感器的目标属性
        fdef.friction = 1.5f;

        body.createFixture(fdef).setUserData("foot");
    }

    public void makeStar(TiledMap map) { //传入一个地图
        System.out.println("makeStar");
        layer = (TiledMapTileLayer) map.getLayers().get("staringround"); //拿到地图中的图层集，然后从图层集中拿到图层名叫做staringround的图层

        bdef = new BodyDef();
        bdef.type = BodyDef.BodyType.StaticBody; //设置刚体的类型为静态，就是不会移动的刚体,类似于地面
        chain = new ChainShape();
        fdef = new FixtureDef();

        fixtureList = new LinkedList<Fixture>();

        int index = 0; //设置下标

        for (int i = 0; i < layer.getHeight(); i++) {
            for (int j = 0; j < layer.getWidth(); j++) { //for循环获取二维数字的地图中所有瓦片
                //判断拿到的瓦片是否为空,判断该地图格是否为空
                if (layer.getCell(j, i) == null || layer.getCell(j, i).getTile() == null) {
                    continue; //如果为空就重新获取
                }

                TiledMapTile tile = layer.getCell(j, i).getTile(); //拿到瓦片

                bdef.position.set(j * tileSize / PPM + tileSize / 2 / PPM, i * tileSize / PPM + tileSize / 2 / PPM); //设置刚体位置
                body = world.createBody(bdef);

                CircleShape circle = new CircleShape(); //圆形
                circle.setRadius(13f / PPM); //设置半径

                fdef.shape = circle;
                fdef.filter.categoryBits = BIT_STAR;
                fdef.filter.maskBits = (short) (BIT_PLAYER | BIT_GROUND);

                Fixture fixture = body.createFixture(fdef);
				fixture.setUserData(index);

				fixtureList.add(fixture);
				
                index++;
            }
        }
    }

    public void killStar(int index) {
        System.out.println("killStar");
        
		int in = 0;
		
		for(int i = 0; i < layer.getHeight(); i++) {
			for(int j = 0; j < layer.getWidth(); j++) {
				if(layer.getCell(j,i) == null || layer.getCell(j,i).getTile() == null) {
					continue;
				}
				
				if(in == index) {
					layer.getCell(j,i).getTile().getTextureRegion().getTexture().dispose();
				}
				
				in++;
			}
		}
		
		fixtureList.get(index).setSensor(true);
    }

    public void makeGround(TiledMap map) {

        TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(0);

        bdef = new BodyDef();
        bdef.type = BodyDef.BodyType.StaticBody;
        chain = new ChainShape();
        fdef = new FixtureDef();

        for (int i = 0; i < layer.getHeight(); i++) {
            for (int j = 0; j < layer.getWidth(); j++) {
                if (layer.getCell(j, i) == null || layer.getCell(j, i).getTile() == null) {
                    continue;
                }

                bdef.position.set(j * tileSize / 2 / PPM + tileSize / 2 / PPM, i * tileSize / 2 / PPM + tileSize / 2 / PPM);
                body = world.createBody(bdef);

                Vector2[] chainList = { //设置链式图形每一个点的位置，它们会以顺时针的方向连接起来
                        new Vector2(j * tileSize / 2 / PPM - tileSize / 2 / PPM, i * tileSize / 2 / PPM + tileSize / 2 / PPM),
                        new Vector2(j * tileSize / 2 / PPM + tileSize / 2 / PPM, i * tileSize / 2 / PPM + tileSize / 2 / PPM),
                        new Vector2(j * tileSize / 2 / PPM + tileSize / 2 / PPM, i * tileSize / 2 / PPM - tileSize / 2 / PPM),
                        new Vector2(j * tileSize / 2 / PPM - tileSize / 2 / PPM, i * tileSize / 2 / PPM - tileSize / 2 / PPM),
                        new Vector2(j * tileSize / 2 / PPM - tileSize / 2 / PPM, i * tileSize / 2 / PPM + tileSize / 2 / PPM)
                };

                chain.createChain(chainList);

                fdef.shape = chain;
                fdef.filter.categoryBits = BIT_GROUND;
                fdef.filter.maskBits = (short) (BIT_PLAYER | BIT_STAR);

                body.createFixture(fdef).setUserData("ground");

            }
        }
    }

    private void init() { //用于初始化成员变量的方法
        world = new World(new Vector2(0, -9.81f), true); //第一个参数:设置世界的重力方向，向下等于9.81，和真实世界一样 第二个参数:是否让刚体休眠
        debug = new Box2DDebugRenderer();
        bdef = new BodyDef();
        fdef = new FixtureDef();

        world.setContactListener(new Box2DContactListener()); //设置监听
    }

    public void update() { //这个用于更新会循环调用
        world.step(1 / 60f, 6, 2);
        debug.render(world, b2dCamera.combined);
    }
}
